package net.kazed.nextaction.database.serialize;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.kazed.nextaction.database.DatabaseHelper;
import net.kazed.nextaction.database.Task;
import net.kazed.nextaction.database.TaskStatus;
import net.kazed.nextaction.database.backup.RestoreDao;

import org.xml.sax.Attributes;

import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class TaskHandler extends AbstractElementHandler implements ElementHandlerContext<RestoreTask> {

   private SQLiteDatabase database;
   private RestoreDao backupDao;
   private RestoreTask currentTask;
   private Map<Integer, Integer> contextIdTranslation;
   private Map<Integer, Integer> taskIdTranslation;

   public TaskHandler(RestoreDao backupDao, SQLiteDatabase database, Map<Integer, Integer> contextIdTranslation) {
      super();
      this.backupDao = backupDao;
      this.database = database;
      this.contextIdTranslation = contextIdTranslation;
      this.taskIdTranslation = new HashMap<Integer, Integer>();

      addElementHandler(RestoreTask.ID, new TaskHandler.TaskIdHandler(this));
      addElementHandler(RestoreTask.DESCRIPTION, new TaskHandler.TaskDescriptionHandler(this));
      addElementHandler(RestoreTask.PARENT_TASK_ID, new TaskHandler.TaskParentTaskIdHandler(this));
      addElementHandler(RestoreTask.DETAILS, new TaskHandler.TaskDetailsHandler(this));
      addElementHandler(RestoreTask.CONTEXT_ID, new TaskHandler.TaskContextIdHandler(this));
      addElementHandler(RestoreTask.COMPLETE, new TaskHandler.TaskCompleteHandler(this));
      addElementHandler(RestoreTask.TYPE, new TaskHandler.TaskTypeHandler(this));
      DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
      addElementHandler(RestoreTask.CREATED, new TaskHandler.CreatedDateHandler(this, dateFormat));
      addElementHandler(RestoreTask.MODIFY_DATE, new TaskHandler.ModifiedDateHandler(this, dateFormat));
      addElementHandler(RestoreTask.START_DATE, new TaskHandler.StartDateHandler(this, dateFormat));
      addElementHandler(RestoreTask.DUE_DATE, new TaskHandler.DueDateHandler(this, dateFormat));
   }

   public RestoreTask getCurrentTask() {
      return currentTask;
   }

   @Override
   public void startElement(String name, Attributes attributes, ParserState state) {
      currentTask = new RestoreTask();
   }

   @Override
   public void endElement(String name, ParserState state) {
      List<Integer> translatedContextIds = new ArrayList<Integer>();
      for (Integer contextId : currentTask.contextIds) {
         if (contextIdTranslation.containsKey(contextId)) {
            translatedContextIds.add(contextIdTranslation.get(contextId));
         } else {
            translatedContextIds.add(contextId);
         }
      }

      if (currentTask.parentTaskId != null) {
         if (taskIdTranslation.containsKey(currentTask.parentTaskId)) {
            currentTask.parentTaskId = taskIdTranslation.get(currentTask.parentTaskId);
         } else {
            currentTask.parentTaskId = null;
         }
      }
      
      Integer contextId = null;
      if (translatedContextIds.size() > 0) {
         contextId = 1;
      } else {
         contextId = null;
      }
      Task task = new Task(currentTask.id, currentTask.description, currentTask.details, contextId, currentTask.parentTaskId,
            currentTask.created, currentTask.modified, currentTask.startDate, currentTask.dueDate, currentTask.order,
            currentTask.completed, currentTask.type);
      ContentValues values = new ContentValues();
      task.toValues(values);
      int count = database.update(DatabaseHelper.TABLE_TASK, values, "_id=" + task.getId(), null);
      if (count == 0) {
         long newTaskId = database.insert(DatabaseHelper.TABLE_TASK, DatabaseHelper.TASK_LIST_PROJECT_MAP
               .get(Task.Column.DESCRIPTION), values);
         taskIdTranslation.put(currentTask.id, (int) newTaskId);
         currentTask.id = (int) newTaskId;
      } else {
         taskIdTranslation.put(currentTask.id, currentTask.id);
      }
      
      backupDao.replaceTaskContexts(currentTask.id, translatedContextIds);

      currentTask = null;
   }

   public RestoreTask getContextData() {
      return currentTask;
   }

   public static class TaskIdHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskIdHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().id = Integer.valueOf(text);
      }
   }

   public static class TaskDescriptionHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskDescriptionHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().description = text;
      }

      @Override
      public boolean isValueEncoded() {
         return true;
      }
   }

   public static class TaskDetailsHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskDetailsHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().details = text;
      }

      @Override
      public boolean isValueEncoded() {
         return true;
      }
   }

   public static class TaskParentTaskIdHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskParentTaskIdHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().parentTaskId = Integer.valueOf(text);
      }
   }

   public static class TaskContextIdHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskContextIdHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().contextIds.add(Integer.valueOf(text));
      }
   }

   public static class TaskCompleteHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskCompleteHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().completed = Boolean.parseBoolean(text);
      }
   }

   public static class TaskTypeHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      public TaskTypeHandler(ElementHandlerContext<RestoreTask> handlerContext) {
         super(handlerContext);
      }

      @Override
      public void characters(String text, ParserState state) {
         getContextData().type = TaskStatus.getEnum(Integer.valueOf(text));
      }
   }

   public static class CreatedDateHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      private DateFormat dateFormat;

      public CreatedDateHandler(ElementHandlerContext<RestoreTask> handlerContext, DateFormat dateFormat) {
         super(handlerContext);
         this.dateFormat = dateFormat;
      }

      @Override
      public void characters(String text, ParserState state) {
         try {
            getContextData().created = dateFormat.parse(text);
         } catch (ParseException e) {
            getContextData().created = null;
         }
      }
   }

   public static class ModifiedDateHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      private DateFormat dateFormat;

      public ModifiedDateHandler(ElementHandlerContext<RestoreTask> handlerContext, DateFormat dateFormat) {
         super(handlerContext);
         this.dateFormat = dateFormat;
      }

      @Override
      public void characters(String text, ParserState state) {
         try {
            getContextData().modified = dateFormat.parse(text);
         } catch (ParseException e) {
            getContextData().modified = null;
         }
      }
   }

   public static class StartDateHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      private DateFormat dateFormat;

      public StartDateHandler(ElementHandlerContext<RestoreTask> handlerContext, DateFormat dateFormat) {
         super(handlerContext);
         this.dateFormat = dateFormat;
      }

      @Override
      public void characters(String text, ParserState state) {
         try {
            getContextData().startDate = dateFormat.parse(text);
         } catch (ParseException e) {
            getContextData().startDate = null;
         }
      }
   }

   public static class DueDateHandler extends AbstractElementHandlerWithContext<RestoreTask> {
      private DateFormat dateFormat;

      public DueDateHandler(ElementHandlerContext<RestoreTask> handlerContext, DateFormat dateFormat) {
         super(handlerContext);
         this.dateFormat = dateFormat;
      }

      @Override
      public void characters(String text, ParserState state) {
         try {
            getContextData().dueDate = dateFormat.parse(text);
         } catch (ParseException e) {
            getContextData().dueDate = null;
         }
      }
   }

}
